#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <linux/input.h>

void ListInputDevice()
{
    int32_t fd;
    int32_t i, j;

    char path[128] = {0};
    char name[128] = {0};
    uint8_t mask[EV_MAX / 8 + 1] = {0};
    uint8_t version[4] = {0};

    for (i = 0; i < 32; i++)
    {
        memset(path, 0, sizeof(path));
        sprintf(path, "/dev/input/event%d", i);

        fd = open(path, O_RDONLY);
        if (fd < 1)
            continue;
        
        ioctl(fd, EVIOCGVERSION, version);
        ioctl(fd, EVIOCGNAME(sizeof(name)), name);
        ioctl(fd, EVIOCGBIT(0, sizeof(mask)), mask);
        printf("\r\n%s: \r\n", path);
        printf("    version: %d.%d.%d \r\n", version[2], version[1], version[0]);
        printf("    name: %s \r\n", name);
        printf("    features: ");
#if 0
        for (j = 0; j < sizeof(mask); j++)
            printf("%02X ", mask[j]);
        printf("\r\n");
#else
        printf("\r\n");
        for (j = 0; j < EV_MAX; j++)
        {
            if (mask[j/8] & (1 << (j%8)))
            {
                printf("      %02X", j);
                switch(j) {
                case EV_SYN: printf(" EV_SYN "); break;
                case EV_KEY: printf(" EV_KEY keys/buttons"); break;
                case EV_REL: printf(" EV_REL relative"); break;
                case EV_ABS: printf(" EV_ABS absolute"); break;
                case EV_MSC: printf(" EV_MSC "); break;
                case EV_SW: printf(" EV_SW switch"); break;
                case EV_LED: printf(" EV_LED leds"); break;
                case EV_SND: printf(" EV_SND sound"); break;
                case EV_REP: printf(" EV_REP repeat"); break;
                case EV_FF: printf(" EV_FF "); break;
                case EV_PWR: printf(" EV_PWR "); break;
                case EV_FF_STATUS: printf(" EV_FF_STATUS "); break;
                }
                printf("\r\n");
            }
        }
#endif

        close(fd);
    }
}

void TestInputDevice(const char *device)
{
    struct input_event event;
    uint8_t data[3];

    int32_t fd = open(device, O_RDONLY);
    if (fd < 0) {
        printf("open %s failed\r\n", device);
        return;
    }

    if (strstr(device, "mice"))
    {
        while (1)
        {
            if (read(fd, &data, sizeof(data)) > 0)
                printf("%d:%d:%d:%d:%d:%d:%d:%d - %d - %d\r\n",
                    (data[0] & (1 << 7)) ? 1 : 0,
                    (data[0] & (1 << 6)) ? 1 : 0,
                    (data[0] & (1 << 5)) ? 1 : 0,
                    (data[0] & (1 << 4)) ? 1 : 0,
                    (data[0] & (1 << 3)) ? 1 : 0,
                    (data[0] & (1 << 2)) ? 1 : 0,
                    (data[0] & (1 << 1)) ? 1 : 0,
                    (data[0] & (1 << 0)) ? 1 : 0,
                    data[1],
                    data[2]);

            // data[0]定义 :
            //   bit 0 - 0/松开 1/按下 鼠标左键按下与否
            //   bit 1 - 0/松开 1/按下 鼠标右键按下与否
            //   bit 2 - 0/松开 1/按下 鼠标滚轮按下与否
            //   bit 3 - 恒为1
            //   bit 4 - 0/正值 1/负值 data[1]数值的正负状态(其实直接用char来取值就可以了)
            //   bit 5 - 0/正值 1/负值 data[2]数值的正负状态(同上)
            //   bit 6 - 恒为0
            //   bit 7 - 恒为0
            // data[1]定义 : 鼠标左右滑动增量,左负,右正
            // data[2]定义 : 鼠标上下滑动增量,下负,上正
        }
    }
    else
    {
        while (1)
        {
            if (read(fd, &event, sizeof(event)) > 0)
                printf("type: %d(%02X), code: %d, value: %d, sec: %ld.%06ld \r\n",
                    event.type,
                    event.type,
                    event.code,
                    event.value,
                    event.time.tv_sec,
                    event.time.tv_usec);
        }
    }

    close(fd);
}
